#!/usr/bin/env bash

### BEGIN ###
# Author: idevz
# Since: 2018/03/12
# Description:   A framework for create a language development environment using parallels vm.
# prlctlc exec golang 'sudo -Hiu z set_up'
#
# Environment variables that control init:
# BI: the base parallels image which you're using to setup, I build one from a nake centos7
#     and also add the most common tools with my daily using.
# PR: your parallels root which set to store your paramllels vms(pvms).
# CAS: set if both clone and set up the pvm at one time, default is "yes" do both at once.
# USI: set if using static ip, or dhcp. default is "yes" to using static ip.
### END ###

set -ex

BASE_IMAGE=${BI:-"centos7-base-1708"}
PARALLELS_ROOT=${PR:-${HOME}"/Documents/Parallels"}
CLONE_AND_SETUP=${CAS:-"yes"}
USING_STATIC_IP=${USI:-"yes"}
BASE_DIR=$(dirname $(cd $(dirname "$0") && pwd -P)/$(basename "$0"))

xnotic() {
	local STATUS=1
	[ ! -z ${2} ] && STATUS=${2}
	echo
	echo ${1} && echo && exit ${STATUS}
}

ynotic() {
	echo
	echo ${1}
}

# SIGSTKFLT
# SIGPOLL
# SIGPWR
# SIGILL SIGTRAP SIGABRT SIGBUS SIGFPE SIGKILL SIGUSR1 SIGSEGV SIGUSR2 SIGPIPE SIGALRM
# SIGTERM SIGCHLD SIGCONT SIGSTOP SIGTSTP SIGTTIN SIGTTOU SIGURG SIGXCPU SIGXFSZ
# SIGVTALRM SIGPROF SIGWINCH SIGSYS
trap "runX_exit $LINENO $BASH_COMMAND; exit" SIGHUP SIGINT SIGQUIT
runX_exit() {
	echo
	local EXIT_MSG="something has happened"
	logger -p notice "$(basename $0) - ${EXIT_MSG}"
	ynotic "${EXIT_MSG}"
	ynotic "$@"
}

[ ! -d ${PARALLELS_ROOT} ] && mkdir -p "${PARALLELS_ROOT}"
type prlctl >/dev/null 2>&1 || xnotic "please make sure that your 'prlctl' works well."

x_clone() {
	[ -z "${1}" ] && xnotic "need a name for your new vm."
	[ "${USING_STATIC_IP}" = 'yes' ] && [ -z "${2}" ] && xnotic "need to set a static ip."
	local HOST_NAME=${1}
	[ ! -z "${3}" ] && BASE_IMAGE="${3}"

	ynotic "start clone ${HOST_NAME}."

	prlctl clone "${BASE_IMAGE}" --name "${HOST_NAME}" --dst "${PARALLELS_ROOT}"
	sleep 1
	prlctl start "${HOST_NAME}"

	# set -e make the shell script exit when any error happens. but except '&&' and '||'
	VM_STATUS=$(_prlctl_exec "${HOST_NAME}" ip addr show >/dev/null 2>&1) || VM_STATUS=1

	ynotic "start check if the vms ${HOST_NAME} is already started."

	until $([ -z ${VM_STATUS} ]); do
		# when pvm started, exec ip command eixt with code 0, but $() express return empty
		# so VM_STATUS is empty, we use -z as a until end condition.
		VM_STATUS=$(_prlctl_exec "${HOST_NAME}" ip addr show >/dev/null 2>&1) || VM_STATUS=1
		sleep 1
		echo -n "."
	done

	ynotic "${HOST_NAME} has started."

	if [ "${USING_STATIC_IP}" = 'yes' ]; then
		[ ! -z "${2}" ] && STATIC_IP=${2}
		ynotic "hostname setting..."

		# _prlctl_exec "${HOST_NAME}" uname -a | grep -Eo '\.(el7)\.' >/dev/null 2>&1 &&
		_prlctl_exec "${HOST_NAME}" hostnamectl set-hostname "${HOST_NAME}"
		# _prlctl_exec "${HOST_NAME}" uname -a | grep -Eo '\.(el6)\.' >/dev/null 2>&1 &&
		# 	_prlctl_exec "${HOST_NAME}" "echo '${HOST_NAME}' | sudo tee -a /etc/sysconfig/network"

		ynotic "eth0 setting..."
		# _prlctl_exec ${HOST_NAME} sudo sed -i 's/BOOTPROTO=\"dhcp\"/BOOTPROTO=\"static\"/g' \
		# /etc/sysconfig/network-scripts/ifcfg-eth0
		_prlctl_exec "${HOST_NAME}" 'sudo sed -i.bak "/BOOTPROTO/d;/IPADDR/d;/NETMASK/d;/GATEWAY/d" /etc/sysconfig/network-scripts/ifcfg-eth0'
		GATEWAY_IP=$(echo "${STATIC_IP}" | grep -Eo '.*[.]')1
		EHT0_CFG=$(
			cat <<CFG
BOOTPROTO="static"
IPADDR="${STATIC_IP}"
NETMASK="255.255.255.0"
GATEWAY="${GATEWAY_IP}"
CFG
		)
		_prlctl_exec ${HOST_NAME} \
			"sudo echo '${EHT0_CFG}' >> /etc/sysconfig/network-scripts/ifcfg-eth0"

		ynotic "/etc/resolv.conf setting..."
		DNS_RESOLV_CFG=$(
			cat <<CFG
# Generated by NetworkManager
search localdomain
nameserver ${GATEWAY_IP}
CFG
		)
		_prlctl_exec ${HOST_NAME} "sudo echo '${DNS_RESOLV_CFG}' >/etc/resolv.conf"
		_prlctl_exec ${HOST_NAME} 'sudo ifdown eth0 && ifup eth0'
	fi
}

_prlctl_exec() {
	[ -z "${1}" ] && xnotic "need a name for your new vm."
	[ -z "${2}" ] && xnotic "empty command."
	# https://stackoverflow.com/questions/33192114/problems-with-prlctl-exec-inside-emacs-shell-mode-window
	# why add `</dev/null` to redirect the std in ?
	prlctl exec "$@" </dev/null
}

x_setup() {
	_prlctl_exec "${1}" "sudo -Hiu z set_up ${2}"
}

x_recreate_profile() {
	_prlctl_exec "${1}" 'sudo -Hiu z set_up rp'
}

x_show_ip() {
	_prlctl_exec "${1}" 'ip addr show'
}

__prlctl_x() {
	prlctl "${1}" "${2}"
}

case ${1} in
t)
	echo "$@"
	;;
new)
	shift
	x_clone "$@"
	;;
nx | newx)
	# using a hosts list is default to using static ip to clone pvms.
	HOST_FILE="${BASE_DIR}/deploy/hosts"
	[ ! -f ${HOST_FILE} ] &&
		xnotic "new x command need a hosts file which format like /etc/hosts."
	PVM_LIST=$(prlctl list -a)
	while read line; do
		echo ${line} | grep -Eo '^#' && continue
		STATIC_IP=$(echo ${line} | cut -f 1 -d ' ')
		HOST_NAME=$(echo ${line} | awk '{print $2}')
		INIT_FILE=$(echo ${line} | awk '{print $3}')
		SET_BASE_IMAGE=$(echo ${line} | awk '{print $4}')
		INIT_FILE=${INIT_FILE//\#/}
		echo "${PVM_LIST}" | grep -Eo " ${HOST_NAME}$" && continue

		if [ ${CLONE_AND_SETUP} = 'yes' ]; then
			PVM_INIT_SHELL="${BASE_DIR}/deploy/${HOST_NAME}/init"
			if [ ! -z ${INIT_FILE} ]; then
				PVM_INIT_SHELL="${BASE_DIR}/deploy/${INIT_FILE}/init"
				# BASE_IMAGE=${BI:-"centos7-docker-base-1708"}
			fi
			[ ! -f ${PVM_INIT_SHELL} ] && continue
			[ -f ${PVM_INIT_SHELL} ] &&
				chmod +x ${PVM_INIT_SHELL} &&
				x_clone ${HOST_NAME} ${STATIC_IP} ${SET_BASE_IMAGE}
			ynotic "start set up your pvm."
			x_setup ${HOST_NAME} ${INIT_FILE}
			ynotic "pvm ${HOST_NAME} set up sucessed."
		else
			x_clone ${HOST_NAME} ${STATIC_IP}
		fi
	done <"${HOST_FILE}"
	;;
run)
	shift
	VM_NAME=${1}
	shift
	_prlctl_exec "${VM_NAME}" "$@"
	;;
set_up)
	x_setup "${2}"
	;;
ip)
	x_show_ip "${2}"
	;;
stop | stp*)
	__prlctl_x stop "${2}"
	;;
stopx | stpx*)
	__prlctl_x stop "${2}"
	__prlctl_x delete "${2}"
	;;
*)
	# exec set_up commands
	CMD=${1}
	HOST_NAME=${2}
	source "${BASE_DIR}/shell/runX.host.sh"
	if _check_pvm_is_alive "${HOST_NAME}"; then
		_prlctl_exec "${HOST_NAME}" "sudo -Hiu z set_up ${CMD}"
		xnotic "set_up executing sucessed ..."
	else
		if ! _check_pvm_is_exist "${HOST_NAME}"; then
			xnotic "there is no pvm named ${HOST_NAME}"
		else
			prlctl start "${HOST_NAME}"
			xnotic "starting the vms ${HOST_NAME} ..."
			_waiting_til_done prlctl exec "${HOST_NAME}" ip addr show
			_prlctl_exec "${HOST_NAME}" "sudo -Hiu z set_up ${CMD}"
			xnotic "set_up executing sucessed ..."
		fi
	fi
	;;
esac
